package miniproj.services.data;

import java.util.*;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import miniproj.models.building.Building;
import miniproj.models.groups.Group;
import miniproj.models.groups.Promotion;
import miniproj.models.groups.Teaching;
import miniproj.models.people.Teacher;
import miniproj.models.reservation.Reservation;
import miniproj.models.room.Room;
import miniproj.services.serialization.SerializedRoom;

/**
 * This singleton class represents the DataContext of the program. It can be
 * loaded from the data file, and stored in this data file. Each simulator share
 * this object.
 * 
 * @author Baptiste Viale
 * 
 */
@XmlRootElement
public class DataContext implements java.io.Serializable {

	private static final long serialVersionUID = -3275622309757758418L;

	// Singleton variable
	private static DataContext dc;

	// Data
	private LinkedList<Building> buildings;

	@XmlJavaTypeAdapter(value = SerializedRoom.class)
	private List<Room> rooms;
	private LinkedList<Reservation> reservations;
	private LinkedList<Group> groups;
	private LinkedList<Teaching> teachings;
	private LinkedList<Teacher> teachers;
	private LinkedList<Promotion> promotions;

	// Serialization tools
	private transient DataWriter dataWriter;
	private transient DataLoader dataLoader;

	/**
	 * Instantiates a new data context. (JavaBeans)
	 */
	public DataContext() {
	}

	// private
	private DataContext(boolean b) {
		this.buildings = new LinkedList<Building>();
		this.rooms = new LinkedList<Room>();
		this.reservations = new LinkedList<Reservation>();
		this.groups = new LinkedList<Group>();
		this.teachings = new LinkedList<Teaching>();
		this.teachers = new LinkedList<Teacher>();
		this.promotions = new LinkedList<Promotion>();
	}

	/**
	 * Gets the data context.
	 * 
	 * @return the data context
	 */
	public static DataContext getDataContext() {
		if (dc == null)
			dc = new DataContext(true);

		return dc;
	}

	/**
	 * Load from file.
	 * 
	 * @param directoryPath
	 *            the directory path of the file
	 * @param fileName
	 *            the file name
	 */
	public void loadFromFile(String directoryPath, String fileName) {
		this.dataLoader = new XMLDataLoader(directoryPath);
		// this.dataLoader = new SpecialDataLoader(directoryPath);
		// this.dataLoader = new StreamDataLoader(directoryPath);

		DataContext d = this.dataLoader.getDataContext(fileName);

		if (d == null)
			return;

		this.buildings = d.buildings;
		this.rooms = d.rooms;
		this.reservations = d.reservations;
		this.groups = d.groups;
		this.teachings = d.teachings;
		this.teachers = d.teachers;
		this.promotions = d.promotions;
	}

	/**
	 * Save in file.
	 * 
	 * @param directoryPath
	 *            the directory path of the file
	 * @param fileName
	 *            the file name
	 */
	public void saveInFile(String directoryPath, String fileName) {
		this.dataWriter = new XMLDataWriter(directoryPath);
		// this.dataWriter = new SpecialDataWriter(directoryPath);
		// this.dataWriter = new StreamDataWriter(directoryPath);

		this.dataWriter.setDataContext(this, fileName);
	}

	/**
	 * Gets the buildings.
	 * 
	 * @return the buildings
	 */
	public LinkedList<Building> getBuildings() {
		return buildings;
	}

	/**
	 * Sets the buildings.
	 * 
	 * @param buildings
	 *            the new buildings
	 */
	@XmlElementWrapper(name = "buildingslist")
	@XmlElement(name = "building")
	public void setBuildings(LinkedList<Building> buildings) {
		this.buildings = buildings;
	}

	/**
	 * Gets the rooms.
	 * 
	 * @return the rooms
	 */
	public List<Room> getRooms() {
		return rooms;
	}

	/**
	 * Sets the rooms.
	 * 
	 * @param rooms
	 *            the new rooms
	 */
	@XmlElementWrapper(name = "roomslist")
	@XmlElement(name = "room")
	public void setRooms(LinkedList<Room> rooms) {
		this.rooms = rooms;
	}

	/**
	 * Gets the reservations.
	 * 
	 * @return the reservations
	 */
	public LinkedList<Reservation> getReservations() {
		return reservations;
	}

	/**
	 * Sets the reservations.
	 * 
	 * @param reservations
	 *            the new reservations
	 */
	@XmlElementWrapper(name = "reservationslist")
	@XmlElement(name = "reservation")
	public void setReservations(LinkedList<Reservation> reservations) {
		this.reservations = reservations;
	}

	/**
	 * Gets the groups.
	 * 
	 * @return the groups
	 */
	public LinkedList<Group> getGroups() {
		return groups;
	}

	/**
	 * Sets the groups.
	 * 
	 * @param groups
	 *            the new groups
	 */
	@XmlElementWrapper(name = "groupslist")
	@XmlElement(name = "group")
	public void setGroups(LinkedList<Group> groups) {
		this.groups = groups;
	}

	/**
	 * Gets the teachings.
	 * 
	 * @return the teachings
	 */
	public LinkedList<Teaching> getTeachings() {
		return teachings;
	}

	/**
	 * Sets the teachings.
	 * 
	 * @param teachings
	 *            the new teachings
	 */
	@XmlElementWrapper(name = "teachingslist")
	@XmlElement(name = "teaching")
	public void setTeachings(LinkedList<Teaching> teachings) {
		this.teachings = teachings;
	}

	/**
	 * Gets the teachers.
	 * 
	 * @return the teachers
	 */
	public LinkedList<Teacher> getTeachers() {
		return teachers;
	}

	/**
	 * Sets the teachers.
	 * 
	 * @param teachers
	 *            the new teachers
	 */
	@XmlElementWrapper(name = "teacherslist")
	@XmlElement(name = "teacher")
	public void setTeachers(LinkedList<Teacher> teachers) {
		this.teachers = teachers;
	}

	/**
	 * Gets the promotions.
	 * 
	 * @return the promotions
	 */
	public LinkedList<Promotion> getPromotions() {
		return promotions;
	}

	/**
	 * Sets the promotions.
	 * 
	 * @param promotions
	 *            the new promotions
	 */
	@XmlElementWrapper(name = "promotionslist")
	@XmlElement(name = "promotion")
	public void setPromotions(LinkedList<Promotion> promotions) {
		this.promotions = promotions;
	}
}
